package com.unitd.frame.spring;

import com.unitd.frame.comm.exception.SpringException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Map;

/**
 * @desc Spring上下文对象容器提供类
 * 此类中,用于手工实例化springBean对象;普通java程序可以从此处获取bean
 * @filename InstanceFactory.java
 * @copyright www.unitd.com
 * @author Hudan
 * @version 1.0
 * @date 2016/10/14
 */
public class SpringInstanceProvider {

	/** Spring的当前上下文对象 */
	private ApplicationContext applicationContext;

	public SpringInstanceProvider() {
	}

	/**
	 * @desc 从ApplicationContext中生成SpringProvider
	 * @param applicationContext Spring的当前上下文对象
	 */
	public SpringInstanceProvider(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	/**
	 * @desc 根据指定的Spring配置文件的路径,初始化Spring实例提供者
	 * @param locations Spring配置文件的路径的集合,Spring将从类路径开始获取这批资源文件
	 */
	public SpringInstanceProvider(String... locations) {
		if(locations != null) {
			applicationContext = new ClassPathXmlApplicationContext(locations);
		}
	}

	/**
	 * @desc 根据指定的Spring的注解类,初始化spring实例提供者
	 * @param annotatedClasses 注解类
	 */
	public SpringInstanceProvider(Class<?>... annotatedClasses) {
		if(annotatedClasses != null) {
			applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
		}
	}

	/**
	 * @desc 根据实例名称,返回指定类型的实例
	 * @param beanName 实例名称
	 * @return 指定类型的实例
	 */
	@SuppressWarnings("unchecked")
	public <T> T getInstance(String beanName) {
		checkApplicationContext();
		return (T) applicationContext.getBean(beanName);
	}

	/**
	 * @desc 根据实例类型,返回指定类型的实例
	 * @param beanClass 实例的类型
	 * @return 指定类型的实例
	 */
	@SuppressWarnings("unchecked")
	public <T> T getInstance(Class<T> beanClass) {
		checkApplicationContext();
		String[] beanNames = applicationContext.getBeanNamesForType(beanClass);
		if (beanNames.length == 0) {
			return null;
		}
		return (T) applicationContext.getBean(beanNames[0]);
	}

	/**
	 * @desc 根据实例类型和实例名称,返回指定类型的实例
	 * @param beanClass 实例的类型
	 * @param beanName 实例名称
	 * @return 指定类型的实例
	 */
	public <T> T getInstance(Class<T> beanClass, String beanName) {
		checkApplicationContext();
		return (T) applicationContext.getBean(beanName, beanClass);
	}

	/**
	 * @desc 根据实例类型,返回指定类型的实例个数
	 * @param beanClass 实例的类型
	 * @return 指定类型的实例
	 */
	public <T> int getInterfaceCount(Class<T> beanClass) {
		checkApplicationContext();
		return applicationContext.getBeanNamesForType(beanClass).length;
	}

	public <T> Map<String, T> getInterfaces(Class<T> beanClass) {
		checkApplicationContext();
		return applicationContext.getBeansOfType(beanClass);
	}

	public ApplicationContext getApplicationContext() {
		checkApplicationContext();
		return applicationContext;
	}

	/**
	 * @desc 校验Spring的上下文对象是否存在
	 */
	private void checkApplicationContext() {
		if(applicationContext == null) {
			throw new SpringException("Spring的applicaitonContext未注入,请在spring-context.xml中定义SpringInstanceProvider");
		}
	}
}